package com.yangyouli.unity_demo_server.container;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.yangyouli.unity_demo_server.annotation.ResponseClass;
import com.yangyouli.unity_demo_server.annotation.ResponseMethod;
import com.yangyouli.unity_demo_server.util.PropertiesHelper;
import com.yangyouli.unity_demo_server.util.ReadStringXml;
import com.yangyouli.unity_demo_server.util.ScannerUtil;

/**
 * 可以通过 controller 类的别名得到类<br>
 * 可以通过 controller 类的别名与方法别名得到方法<br>
 * 单例模式
 * @author 24279
 *
 */
public class ControllerContainer {
	// 存储所有的被 ResponseClass 注解的 Controller 实例 key 为 注解的 value
	private Map<String, Object> controllerMap = new HashMap<String, Object>();
	
	// 存储 controllerMap 中被 ResponseMethod 注解的方法的 Method 对象。key 为类的注解的 value 值, 内层的 key 为方法的注解的 value 值
	private Map<String, Map<String, Method>> controllerMethodMap = new HashMap<String, Map<String, Method>>();
	
	// 存储要扫描的包的信息的节点在 xml 中的路径
	private String[] nodePaths = new String[] { "/container/controller-package/package" };
	
	Logger log = Logger.getLogger(ControllerContainer.class);
	
	ControllerContainer () {
		init();
	}
	
	/**
	 * 初始化
	 */
	private void init () {
		// 得到 ContainerConfig.xml 配置文件的路径
		String configPath = PropertiesHelper.getPropertiesValue("ContainerConfig");
		// 得到要扫描的包的路径
		Map<String, List<String>> pathMap = ReadStringXml.getNodesValues(configPath, nodePaths);
		for (String path : nodePaths) {
			List<String> packagePathsList = pathMap.get(path);
			// 扫描并添加这些包路径下的所有被 ResponseClass 注解的类
			for (String packagePath : packagePathsList) {
				injectBeAnnotatedClass(packagePath);
			}
		}
	}
	
	/**
	 * 根据 ControllerName 得到 Controller 对象
	 * @param controllerName
	 * @return
	 */
	Object getController (String controllerName) {
		Object baseController = controllerMap.get(controllerName);
		if (baseController == null) {
			System.err.println("无法找到 controllerName[" + controllerName + "] 对应的 Controller，请检查名字是否正确");
			return null;
		}
		return baseController;
	}
	
	/**
	 * 根据 ControllerName 与 MethodName 得到 Controller 下的某个方法对象
	 * @param controllerName
	 * @param methodName
	 * @return
	 */
	Method getMethod (String controllerName, String methodName) {
		Map<String, Method> methodMap = controllerMethodMap.get(controllerName);
		if (methodMap == null) {
			System.err.println("无法找到 controllerName[" + controllerName + "] 对应的 methodMap，请检查名字是否正确");
			return null;
		}
		Method method = methodMap.get(methodName);
		if (method == null) {
			System.err.println("无法找到 methodName[" + methodName + "] 对应的 Method 对象，请检查名字是否正确");
			return null;
		}
		return method;
	}
	
	/**
	 * 将指定包下被 ResponseClass 注解的类的实例（通过反射得到）添加到 controllerMap 中
	 * @param packagePath 包名
	 */
	private void injectBeAnnotatedClass (String packagePath) {
		List<String> classWholeName = ScannerUtil.scanPackage(packagePath);
		try {
			// for 循环加载实例
			for (String classStr : classWholeName) {
				Class<?> controllerClass = Class.forName(classStr);
				// 如果被 ResponseClass 注解
				if (controllerClass.isAnnotationPresent(ResponseClass.class)) {
					// 实例化该类的对象并且注入属性
					Object controllerObj = controllerClass.newInstance();
					// 得到注解的 value
					String value = getAnnotationValueOrClassName(controllerClass, ResponseClass.class);
					// 将本实例添加到 controllerMap 中
					controllerMap.put(value, controllerObj);
					log.debug("创建 controller 对象：" + controllerClass.getName());
					
					// 将本类的所有方法添加到 controllerMethodMap 中
					Method[] methods = controllerClass.getMethods();
					// 存储一个类中的方法集合
					Map<String, Method> methodsOfController = new HashMap<String, Method>(); 
					for (Method m : methods) {
						// 如果方法被 ResponseMethod 注解
						if (m.isAnnotationPresent(ResponseMethod.class)) {
							// 得到 method 的别名（注解的 value）或名字
							String annotationValue = getAnnotationValueOrMethodName(m, ResponseMethod.class);
							// 添加该方法到 methodsOfController 中
							methodsOfController.put(annotationValue, m);
						}
					}
					// 将 methodsOfController 添加到 controllerMethodMap 中
					controllerMethodMap.put(value, methodsOfController);
				}
			}
		} catch (Exception e) {
			log.error("将指定包下被 ResponseClass 注解的类的实例（通过反射得到）添加到 controllerMap 中发生异常", e);
		}
	}
	
	/**
	 * 返回被注解的类上的注解的 value 值，如果 value 为空，则返回类名（首字母小写）
	 * @param controllerClass
	 * @param annotationClass
	 * @return
	 */
	private String getAnnotationValueOrClassName (Class<?> controllerClass, Class<ResponseClass> annotationClass) {
		String value = null; 
		// 得到注解的 value, 赋值给 identify
		value = controllerClass.getAnnotation(annotationClass).value();
		// 如果没有得到注解内的 value 值，则赋值为类的名称，首字母小写
		if (value.equals("") || value == null) {
			String className = controllerClass.getSimpleName();
			// 获取类名的第一个单词且为小写
			String firstChar = className.substring(0, 1).toLowerCase();
			// 将 className 的第一个单词变为小写并赋值给 value
			value = firstChar + className.substring(1, className.length());
		}
		return value;
	}
	
	/**
	 * 返回被注解的方法上的注解的 value 值，如果 value 为空，则返回方法名
	 * @param methodClass
	 * @param annotationClass
	 * @return
	 */
	private String getAnnotationValueOrMethodName (Method method, Class<ResponseMethod> annotationClass) {
		String value = null; 
		// 得到注解的 value, 赋值给 identify
		value = method.getAnnotation(annotationClass).value();
		// 如果没有得到注解内的 value 值，则赋值为方法的名称
		if (value.equals("") || value == null) {
			value = method.getName();
		}
		return value;
	}

	Map<String, Object> getControllerMap() {
		return controllerMap;
	}
}
